#include "headers/stdafx.h"
#include "headers/GxIAPI.h" 
#include "headers/DxImageProc.h"
#include "headers/camera.hpp"

#include "headers/all_control_define.hpp"

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>  
#include <iostream>
#include <ctime>

using namespace cv;
using namespace std;

typedef unsigned char       BYTE;

GX_DEV_HANDLE       m_hDevice;             
BYTE* m_pBufferRaw;         
BYTE* m_pBufferRGB;          
int64_t             m_nImageHeight;          
int64_t             m_nImageWidth;         
int64_t             m_nPayLoadSize;
int64_t             m_nPixelColorFilter;     


GX_STATUS			emStatus = GX_STATUS_SUCCESS;
GX_OPEN_PARAM		openParam;
uint32_t			nDeviceNum = 0;

Mat frame;

volatile int doubleBufferDealingIndex;
Mat image[2];
volatile int read_flag = 0;
volatile int write_flag = 0;

static void GX_STDC OnFrameCallbackFun(GX_FRAME_CALLBACK_PARAM* pFrame)
{
	if (pFrame->status == 0)
	{	
		read_flag = 1;
		memcpy(m_pBufferRaw, pFrame->pImgBuf, pFrame->nImgSize);
		
		DxRaw8toRGB24(m_pBufferRaw
			, m_pBufferRGB
			, (VxUint32)(m_nImageWidth)
			, (VxUint32)(m_nImageHeight)
			, RAW2RGB_NEIGHBOUR
			, DX_PIXEL_COLOR_FILTER(m_nPixelColorFilter)
			, false);
		if(read_flag == 1 && write_flag == 0){
		memcpy(frame.data, m_pBufferRGB, m_nImageWidth * m_nImageHeight * 3);
		image[doubleBufferDealingIndex] = frame.clone(); 
		read_flag = 0;
		write_flag = 1;
		}
	}
	return;
}

bool init_Camera() {
	char str1[] = "1";
	openParam.accessMode = GX_ACCESS_EXCLUSIVE;
	openParam.openMode = GX_OPEN_INDEX;
	openParam.pszContent = str1;
	
	emStatus = GXInitLib();
	if (emStatus != GX_STATUS_SUCCESS)
	{
		return false;
	}
	
	emStatus = GXUpdateDeviceList(&nDeviceNum, 500); 
	if ((emStatus != GX_STATUS_SUCCESS) || (nDeviceNum <= 0))
	{
		return false;
	}
	
	emStatus = GXOpenDevice(&openParam, &m_hDevice);

	std::cout << "GXOpenDevice: " << emStatus << endl;
	
	if (emStatus < 0)
	{
		return false;
	}
	
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_ACQUISITION_MODE, GX_ACQ_MODE_CONTINUOUS);
#if !TRIGGER_ON
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_TRIGGER_SWITCH, GX_TRIGGER_SWITCH_OFF);
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_TRIGGER_MODE, GX_TRIGGER_MODE_OFF);	//�رմ���ģʽ 
#else 
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_TRIGGER_MODE, GX_TRIGGER_MODE_ON);	//�򿪴���ģʽ 
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_TRIGGER_SWITCH, GX_TRIGGER_SWITCH_ON);	//���ⴥ��ģʽ 
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_TRIGGER_SOURCE, GX_TRIGGER_SOURCE_LINE2);	//���ô���ԴLINE2
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_TRIGGER_ACTIVATION, GX_TRIGGER_ACTIVATION_RISINGEDGE);
	emStatus = GXSetFloat(m_hDevice, GX_FLOAT_TRIGGER_FILTER_RAISING, 0.0f);
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_TRIGGER_SELECTOR, GX_ENUM_TRIGGER_SELECTOR_FRAME_START);	//�������ͣ��ɼ�һ֡
#endif
	emStatus = GXSetInt(m_hDevice, GX_INT_ACQUISITION_SPEED_LEVEL, 1);
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_BALANCE_RATIO_SELECTOR, GX_BALANCE_RATIO_SELECTOR_RED);
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_BALANCE_WHITE_AUTO, GX_BALANCE_WHITE_AUTO_CONTINUOUS);
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_COLOR_CORRECT, GX_COLOR_CORRECT_ON);
	bool      bColorFliter = false;
	
	emStatus = GXGetInt(m_hDevice, GX_INT_PAYLOAD_SIZE, &m_nPayLoadSize);
	
	emStatus = GXGetInt(m_hDevice, GX_INT_WIDTH, &m_nImageWidth);
	
	emStatus = GXGetInt(m_hDevice, GX_INT_HEIGHT, &m_nImageHeight);
	GXSetFloat(m_hDevice, GX_FLOAT_EXPOSURE_TIME, EXP_TIME);		//����ع�ʱ�� 
												// ��
	if(frame.data)frame.release(); 
	frame.create(m_nImageHeight, m_nImageWidth, CV_8UC3);
	std::cout << '(' << m_nImageWidth << ',' << m_nImageHeight << ')' << endl;
	
	bool m_bColorFilter;
	emStatus = GXIsImplemented(m_hDevice, GX_ENUM_PIXEL_COLOR_FILTER, &m_bColorFilter);
	if (m_bColorFilter)
	{
		emStatus = GXGetEnum(m_hDevice, GX_ENUM_PIXEL_COLOR_FILTER, &m_nPixelColorFilter);
	}
	m_pBufferRGB = new BYTE[(size_t)(m_nImageWidth * m_nImageHeight * 3)];
	if (m_pBufferRGB == NULL)
	{
		return false;
	}
	
	m_pBufferRaw = new BYTE[(size_t)m_nPayLoadSize];
	if (m_pBufferRaw == NULL)
	{
		delete[]m_pBufferRGB;
		m_pBufferRGB = NULL;
		return false;
	}
	
	emStatus = GXRegisterCaptureCallback(m_hDevice, NULL, OnFrameCallbackFun);
	
	emStatus = GXSendCommand(m_hDevice, GX_COMMAND_ACQUISITION_START);
	std::cout << "succeed" << endl;
	return true;
}

bool close_Camera(){
	emStatus = GXSendCommand(m_hDevice, GX_COMMAND_ACQUISITION_STOP);
	
	emStatus = GXUnregisterCaptureCallback(m_hDevice);
	if (m_pBufferRGB != NULL)
	{
		delete[]m_pBufferRGB;
		m_pBufferRGB = NULL;
	}
	if (m_pBufferRaw != NULL)
	{
		delete[]m_pBufferRaw;
		m_pBufferRaw = NULL;
	}
	emStatus = GXCloseDevice(m_hDevice);
	emStatus = GXCloseLib();

	return true;
}

bool get_line_state(int Line_num){
	emStatus = GX_STATUS_SUCCESS;
	bool now_status = false;
	//GX_FLOAT_RANGE filter_range;
	//emStatus = GXGetFloat(m_hDevice, GX_FLOAT_TRIGGER_FILTER_RAISING, &filter_range);
	
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_LINE_SELECTOR, Line_num);
	emStatus = GXSetEnum(m_hDevice, GX_ENUM_LINE_MODE, GX_ENUM_LINE_MODE_INPUT);
	emStatus = GXGetBool(m_hDevice, GX_BOOL_LINE_STATUS, &now_status);

	
	return now_status;
}

bool wait_frame(Mat &cur_frame) {

	static double t_1, t_2 = 0, T;
	t_1 = 0;T = 0;
	while (write_flag == 0){
		printf("Line2 status %i\n", get_line_state(2));
		if(t_1 != 0)t_2 = (double(long(clock())) / double(long(CLOCKS_PER_SEC))) - t_1;
		t_1 = double(long(clock())) / double(long(CLOCKS_PER_SEC));
		T += t_2;
		if(T > 3.5){
			close_Camera();
			return false;
		}
	};
	write_flag = 0;
	doubleBufferDealingIndex = !doubleBufferDealingIndex;
	cur_frame = image[!doubleBufferDealingIndex].clone();
	
	if(cur_frame.cols < 10){
		close_Camera();
		return false;
	}

	return true;
}
